
/* Includes ------------------------------------------------------------------*/
#include "includes.h"
#include "utype.h"
#include "stm32f10x_adc.h"
#include "myRtos.h"
#include "MovingAverage.h"
#include "modbus.h"
#include "parm.h"
#include "flash_pb.h"

#define  V3_STD_COUNT        ((3000L*4096)/3300)
#define  V01_STD_COUNT       ((100L*4096)/3300)

typedef struct {
  uint16_t ref_value[2];     // 3V input count
  uint16_t ref_count[2];     // 3V input count  
  uint16_t zero_count[2];   //  0 V input count
  uint16_t Value[2];
  uint16_t Raw_Value[2];
  uint32_t ma_hour_total;
} ADC_WM;

static ADC_WM  Adc;
static MovingAverageFilter FilterData[2];
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
//#define ADC1_DR_Address    ((uint32_t)0x4001244C)

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
ADC_InitTypeDef ADC_InitStructure;

   
/* Private function prototypes -----------------------------------------------*/
 
/* Private functions ---------------------------------------------------------*/

/**
  * @brief   Main program
  * @param  None
  * @retval None
  */
static void RCC_Configuration(void);
static void GPIO_Configuration(void);

void Adc_Init(void)
{
  /* System clocks configuration ---------------------------------------------*/
  RCC_Configuration();

  /* GPIO configuration ------------------------------------------------------*/
  GPIO_Configuration();

  /* ADC1 configuration ------------------------------------------------------*/
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStructure);
  /* ADC1 regular channels configuration */ 
  ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_239Cycles5); 
  ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_239Cycles5);   
  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);
  /* Enable Vrefint channel17 */
  ADC_TempSensorVrefintCmd(ENABLE);

  /* Enable ADC1 reset calibaration register */   
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));

  /* Start ADC1 calibaration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));
  FilterData[0].init(8); // averaged by 8 times
  FilterData[1].init(8); // averaged by 8 times
}

static const uint16_t Channel_sel[2] = {ADC_Channel_8,ADC_Channel_9};

static void Set_Adc1_Channel(uint16_t Channel)
{
  ADC1->SQR3 = (ADC1->SQR3 & (~(0x1f)))|Channel;
}

static uint16_t Calibration(uint16_t Value, uint16_t ch)
{
  int tmp;
  tmp = Value;
  tmp = (tmp-Adc.zero_count[ch])*Adc.ref_value[ch]/(Adc.ref_count[ch]-Adc.zero_count[ch]);
  if(tmp<0) tmp = 0;
  return tmp;
}

#define   ADC_CAL_FLAG           0x1257
#define   CAL_ZERO_VOLT          1
#define   CAL_REF_VOLT           2          // voltage
#define   CAL_REF_AMP            3          // current
#define   CAL_CLEAR_MA           4
#define   CAL_ZERO_AMP           5
#define   CAL_UPDATE             1234

void AdcTask( void *pvParameters )
{
  portTickType TaskTimer;
  
  if(ParmData.adc_cal_flag == ADC_CAL_FLAG){
   Adc.ref_value[0] = ParmData.ref_value_ch8;
   Adc.ref_value[1] = ParmData.ref_value_ch9;
   Adc.ref_count[0] = ParmData.ref_count_ch8;
   Adc.ref_count[1] = ParmData.ref_count_ch9; 
   Adc.zero_count[0] = ParmData.zero_count_ch8;
   Adc.zero_count[1] = ParmData.zero_count_ch9;
  }
  else {
   Adc.ref_value[0] = 3000;  // 3V input
   Adc.ref_value[1] = 3000;
   Adc.ref_count[0] = V3_STD_COUNT;
   Adc.ref_count[1] = V3_STD_COUNT; 
   Adc.zero_count[0] = 0;
   Adc.zero_count[1] = 0;   
  }
  Reg4xxxx[REF_VOLT_REG] =  Adc.ref_value[0] ;
  Reg4xxxx[REF_CURRENT_REG] = Adc.ref_value[1];  
  TaskTimer = xTaskGetTickCount ();
  for(int i=0;;){
     Set_Adc1_Channel(Channel_sel[i]);
//     ADC_SoftwareStartConvCmd(ADC1, ENABLE);
     while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)== SET){
       ADC_ClearFlag(ADC1,ADC_FLAG_EOC);
     }
     ADC_Cmd(ADC1,ENABLE);
     //GPIO_WriteBit(GPIOB, GPIO_Pin_3,Bit_RESET);
     while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)== RESET) {
       Yield();
     }
     //GPIO_WriteBit(GPIOB, GPIO_Pin_3,Bit_SET);
     ADC_ClearFlag(ADC1,ADC_FLAG_EOC);
     Adc.Raw_Value[i] = FilterData[i].process((int)ADC_GetConversionValue(ADC1));
     Adc.Value[i] = Calibration(Adc.Raw_Value[i],i);
     Reg4xxxx[VOLTAGE_VAL_REG+i] = Adc.Value[i];
     Reg4xxxx[VOLTAGE_COUNT_REG+i] = Adc.Raw_Value[i];
     if(i == 1) {
           Adc.ma_hour_total += Adc.Value[1];   // unit in 10 ma
           Reg4xxxx[MA_HOUR_REG] = Adc.ma_hour_total/3600;
     }
     i = (i) ? 0:1;
     vTaskDelayUntil( &TaskTimer, 50 );  // loop once every 50 ms
     GPIO_WriteBit(GPIOA, GPIO_Pin_12,(BitAction)i); // flash test pin
     switch(Reg4xxxx[CAL_FLAG_REG]){
        case CAL_ZERO_VOLT:
             Adc.zero_count[0] = Adc.Raw_Value[0];
             break;
        case CAL_ZERO_AMP:
             Adc.zero_count[1] = Adc.Raw_Value[1];
             break;             
        case CAL_REF_VOLT:
             Adc.ref_count[0] = Adc.Raw_Value[0];
             Adc.ref_value[0] = Reg4xxxx[REF_VOLT_REG];             
             break;
        case CAL_REF_AMP:
             Adc.ref_count[1] = Adc.Raw_Value[1];
             Adc.ref_value[1] = Reg4xxxx[REF_CURRENT_REG];             
             break;             
        case CAL_CLEAR_MA:
             Adc.ma_hour_total = 0;
             break;
        case CAL_UPDATE:
             Adc.ref_value[0] = Reg4xxxx[REF_VOLT_REG];
             Adc.ref_value[1] = Reg4xxxx[REF_CURRENT_REG];
             ParmData.ref_value_ch8 = Adc.ref_value[0] ;
             ParmData.ref_value_ch9 = Adc.ref_value[1];
             ParmData.ref_count_ch8 = Adc.ref_count[0];
             ParmData.ref_count_ch9 = Adc.ref_count[1]; 
             ParmData.zero_count_ch8 = Adc.zero_count[0];
             ParmData.zero_count_ch9 = Adc.zero_count[1];
             ParmData.adc_cal_flag = ADC_CAL_FLAG;
             FlashPBSave((INT8U*)&ParmData);
             break;             
     }
     Reg4xxxx[CAL_FLAG_REG] = 0;
  }
}

int Get_Adc_Value(int Channel)
{
  return Adc.Value[Channel];
}

/**
  * @brief  Configures the different system clocks.
  * @param  None
  * @retval None
  */
static void RCC_Configuration(void)
{
  /* ADCCLK = PCLK2/4 */
  RCC_ADCCLKConfig(RCC_PCLK2_Div4); 
  /* Enable ADC1, ADC2 and GPIOC clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  
}

/**
  * @brief  Configures the different GPIO ports.
  * @param  None
  * @retval None
  */
static void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* Configure PC.01, PC.02 and PC.04 (ADC Channel11, Channel12 and Channel14)
    as analog input ----------------------------------------------------------*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
}


